package com.javabaas.server.novel_server.config;

import com.javabaas.server.novel_server.annotate.SerializedField;
import com.javabaas.server.novel_server.common.Constant;
import org.apache.log4j.Logger;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

@ControllerAdvice(basePackages = "com.javabaas.server.novel_server")
public class ZPResponseBodyAdvice implements ResponseBodyAdvice {

    private Logger logger = Logger.getLogger(ZPResponseBodyAdvice.class);

    //包含项
    private String[] includes = {};

    //排除项
    private String[] excludes = {};

    //是否加密
    private boolean encode = false;


    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        //重新初始化为默认值
        includes = new String[]{};
        excludes = new String[]{};
        encode = false;
        if (o == null) {
            return null;
        }
        Map<String, Object> map;
        if (o instanceof Map) {
            map = (Map<String, Object>) o;
        }else {
            return o;
        }
        if (map.get(Constant.KEY_RES_RESULT) == null) {
            return o;
        }
        Object retObj = map.get(Constant.KEY_RES_RESULT);
        // 从方法处理器中获取出要调用的方法
        Method method = methodParameter.getMethod();
        // 获取出方法上的SerializedField注解
        SerializedField serializedField = method.getAnnotation(SerializedField.class);
        if (serializedField != null) {
            includes = serializedField.includes();
            excludes = serializedField.excludes();
            encode = serializedField.encode();
            if (includes.length == 0 && excludes.length ==0 ) {
                return o;
            }
            if (retObj instanceof List) {
                //list
                List list = (List)retObj;
                map.put(Constant.KEY_RES_RESULT, retObj);
                try {
                    retObj = handleList(list);
                    map.put(Constant.KEY_RES_RESULT, retObj);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }else {
                try {
                    retObj = handleSingleObject(retObj);
                    map.put(Constant.KEY_RES_RESULT, retObj);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return map;
    }


    private List handleList(List list) throws IllegalAccessException {
        List retList = new ArrayList<Object>();
        for (Object o: list) {
            Object retObj = handleSingleObject(o);
            retList.add(retObj);
        }
        return retList;
    }


    /**
    * 处理单个对象
    */
    private Object handleSingleObject(Object o) throws IllegalAccessException {
        Map<String,Object> map = new HashMap<String, Object>();
        Field[] fields = o.getClass().getDeclaredFields();
        for (Field field: fields) {
            field.setAccessible(true);
            //如果未配置表示全部的都返回
            if (includes.length > 0) {
                //考虑包含字段
                if (Arrays.asList(includes).contains(field.getName())) {
                    map.put(field.getName(), field.get(o));
                }
            }else if (excludes.length > 0){
                if (!Arrays.asList(excludes).contains(field.getName())) {
                    map.put(field.getName(), field.get(o));
                }
            }
        }
        return map;
    }

}
